/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_Studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#include "pch.h"
#include "代码模块.h"
#include "文件构建路径.h"

static std::map<std::u16string, S_代码模块> g模块容器;
static std::set<std::string> g模块搜索路径;

S_代码模块& f_model_构建模块(const std::u16string& 模块名称) {
    if(g模块容器.find(模块名称) != g模块容器.end()){
        std::cout<<"编译错误:以存在模块\n";
    }
    return g模块容器[模块名称];
}

bool f_model_添加模块结构(S_代码模块& 模块, const std::u16string& 结构声明) {
    auto& model = 模块.类型声明;
    if(model.find(结构声明) != model.end()){
        model.insert(结构声明);
        return true;
    }
    return false;
}

bool f_model_添加模块函数(S_代码模块& 模块, const std::u16string& 函数声明) {
    auto& model = 模块.函数声明;
    if(model.find(函数声明) != model.end()){
        model.insert(函数声明);
        return true;
    }
    return false;
}

static void f_model_保存模块(const std::filesystem::path& path){
    FILE* file = fopen(path.c_str(), "wb");
    if(file){
        fclose(file);
    }
}

static void f_model_加载模块( 
    const std::filesystem::path& path
    , std::set<std::filesystem::path>& paths
    , S_代码模块& md
    //, std::vector<std::u16string>& 模块分区
    ){
    FILE* file = fopen(path.c_str(), "rb");
    if(file){
        auto data = f_file_r_u16Str(file);

        //依赖模块
        auto 导入模块名称 = f_export_Mdl(data);
        for(auto& 模块名称 : 导入模块名称){
            if(模块名称.back() == "*") {
                模块名称.pop_back();
                auto 当前路径 = path;
                for(auto& e : 模块名称) {
                    当前路径 /= e;
                }
                f_model_导入目录下所有模块(当前路径);
                continue;
            }

            auto key = f_model_模块名称键值(模块名称);
            if(g模块容器.find(key) == g模块容器.end()){
                f_model_导入模块(paths, 导入模块名称, g模块容器[key]);
            }
        }
        

        //模块名称
        auto 分区模块 = f_mod_分区模块名(data);

        //if(模块分区.back() == u"*") {
        //} else {
        //    for(auto& name : 模块分区){
        //    }
        //}
        

        //分区名称

        //函数声明

        //结构声明

        //变量定义

        fclose(file);
    }
    return;
}

void f_model_导入目录下所有模块(
    const std::filesystem::path& path
    , std::set<std::filesystem::path>& paths
    , const std::u16string& 模块名称
    ){
    auto 文件 = f_file_get所有文件(path);
    for(auto name : 文件) {
        auto key = 模块名称 + name;
        if(g模块容器.find(key) == g模块容器.end()){
            f_model_加载模块(path / name, paths, g模块容器[key]);
        }
    }
    auto 文件夹 = f_file_get所有文件夹(path);
    for(auto name : 文件夹) {
        f_model_导入目录下所有模块(path / name, paths, 模块名称 + name + u"::");
    }
}

void f_model_导入模块(std::filesystem::path& paths
    , std::vector<const std::u16string>& 模块名称
    ) {
    bool 找到文件 = false;
    
    std::u16string key;
    for(auto path : paths){
        
        for(auto name : 模块名称) {
            if(name == u"*") {
                f_model_导入目录下所有模块(path, "");
                return ;
            }
            path /= name;

            if(f_file_是否为目录(path)){
                continue;
            } else if(f_file_是否为文件(path + ".m")){
                key = name;
                找到文件 = true;
                break;
            }
        }

        if(key.size() && g模块容器.find(key) == g模块容器.end()){
            f_model_加载模块(path.string() + ".m", paths, g模块容器[key]);
            return ;
        }
    }
    return ;
}

//void f_导入依赖模块(std::set<std::filesystem::path>& paths, const std::u16string& name){
//    for(auto path : paths){
//        auto key = path.u16string() + "::" + name;
//        if(g模块容器.find(key) == g模块容器.end()){
//            path /= name;
//            if(f_file_是否为文件夹(path)){
//                f_model_导入目录下所有模块(path);
//            } else {
//                f_model_加载模块(g模块容器[key], path.string() + ".m");
//            }
//        } else {
//            break;
//        }
//    }
//}

void f_解析导入模块代码(std::vector<std::u16string>::iterator& it
                , std::vector<std::u16string>::iterator& end
                , S_当前文件导入模块& 模块
                , const std::u16string& 工程名称
                ) {
    
    auto 导入的模块名称 = f_代码切片(it, end, ";");
    if(g模块容器.find(导入的模块名称) == g模块容器.end()){
        auto 模块名称 = 导入的模块名称;
        f_符号分割(模块名称, "::");
        
        //查找文件
        auto paths = f_codefile_取模块文件(工程名称);
        f_model_导入模块(paths, 模块名称);
    }
    
    //模块导入到当前文件
    auto& 当前导入模块 = g模块容器[导入的模块名称];
    if(导入的模块名称.back() == u"*"){
        for (auto& e : 当前导入模块.类型声明) {
            if(模块.导入所有模块.类型声明.find(e) == 模块.导入所有模块.类型声明.end()) {
                模块.导入所有模块.类型声明.insert(e);
            } else {
                std::cout<<"编译错误:导入模块重复的类型声明 "<<e<<"\n";
            }
        }
        for (auto& e : 当前导入模块.函数声明) {
            if(模块.导入所有模块.函数声明.find(e) == 模块.导入所有模块.函数声明.end()) {
                模块.导入所有模块.函数声明.insert(e);
            } else {
                std::cout<<"编译错误:导入模块重复的函数声明 "<<e<<"\n";
            }
        }
        for (auto& e : 当前导入模块.全局变量) {
            if(模块.导入所有模块.全局变量.find(e) == 模块.导入所有模块.全局变量.end()) {
                模块.导入所有模块.全局变量.insert(e);
            } else {
                std::cout<<"编译错误:导入模块重复的全局变量 "<<e<<"\n";
            }
        }
        //模块.导入所有模块.insert(&当前导入模块);
    } else {
        模块.导入模块[导入的模块名称] = &当前导入模块;
    }
    //f_model_加载模块(导入的模块名称);
}

void f_model_保存模块(const std::string path) {
    if(g模块搜索路径.find(path) == g模块搜索路径.end()){
        g模块搜索路径.insert(path);
    }
}


